﻿using System;
using System.ComponentModel;
using System.Text.RegularExpressions;
using DSLPedProjectWizard.Messages;
using DSLPedProjectWizard.Views;
using Dsl.Ped.Common;
using System.Collections.Generic;
using GalaSoft.MvvmLight.Messaging;

namespace DSLPedProjectWizard.ViewModels
{
    /// <summary>
    /// Wizard page that let the user select a specific extension. This is the
    /// view model of <see cref="SettingsWizardView"/>
    /// </summary>
    public class SettingsWizardViewModel : ViewModelBase, IDataErrorInfo
    {
        /// <summary>
        /// <see cref="Messenger"/> for the communication between wizard pages
        /// </summary>
        private Messenger messenger;

        /// <summary>
        /// Default name of the language
        /// </summary>
        private string languageName = "MyDsl";

        /// <summary>
        /// Defajl Xml namespace of the language
        /// </summary>
        private string languageXmlNamespace = "http://myDslNamespace";

        private Dictionary<string, string> errorsDictionary = new Dictionary<string, string>();

        /// <summary>
        /// Default language description
        /// </summary>
        private string languageDescription = "AddIn implementing my custom DSL. Add the proper description here";

        /// <summary>
        /// Initializes a new instance of the <see cref="SettingsWizardViewModel"/> class.
        /// </summary>
        /// <param name="messenger"><see cref="Messenger"/> for the communication with a main wizard page</param>
        public SettingsWizardViewModel(Messenger messenger)
        {
            this.messenger = messenger;
        }

        /// <summary>
        /// Gets or sets the name of a language
        /// </summary>
        public string LanguageName
        {
            get
            {
                return this.languageName;
            }
            set
            {
                this.languageName = value;
                RaisePropertyChanged(() => LanguageName);
                
                messenger.Send<CheckFinishMessage>(new CheckFinishMessage());
            }
        }

        /// <summary>
        /// Gets or sets the default xml namespace of the language
        /// </summary>
        public string LanguageXmlNamespace
        {
            get
            {
                return this.languageXmlNamespace;
            }
            set
            {
                this.languageXmlNamespace = value;
                RaisePropertyChanged(() => LanguageName);

                messenger.Send<CheckFinishMessage>(new CheckFinishMessage());
            }
        }

        /// <summary>
        /// Gets or sets the description of a language
        /// </summary>
        public string LanguageDescription
        {
            get
            {
                return this.languageDescription;
            }
            set
            {
                languageDescription = value;
                RaisePropertyChanged(() => LanguageDescription);

                messenger.Send<CheckFinishMessage>(new CheckFinishMessage());
            }
        }

        /// <summary>
        /// Gets the transformation of <see cref="errorsDictionary"/> into the list of errors displayed in the view
        /// </summary>
        public List<string> ValidationErrors
        {
            get
            {
                var errors = new List<string>();
                foreach (var key in errorsDictionary.Keys)
                {
                    errors.Add(string.Format("*{0}: {1}", key, errorsDictionary[key]));
                }

                return errors;
            }
        }

        /// <summary>
        /// Check if the model is valid
        /// </summary>
        /// <returns>True if the model is valid</returns>
        public bool IsValid()
        {
            return (this.ValidateLanguageName() == null && this.ValidateLanguageXmlNamespace() == null);
        }

        /// <summary>
        /// Validate <see cref="LanguageName"/>
        /// </summary>
        /// <returns>Null if the <see cref="LanguageName"/> is valid, string containing an error otherwise</returns>
        private string ValidateLanguageName()
        {
            if (string.IsNullOrEmpty(languageName))
            {
                return "Must not be null";
            }
            if (!Regex.IsMatch(languageName, @"^[a-zA-Z]+$"))
            {
                return "Language Name must be composed of letters only";
            }

            return null;
        }

        /// <summary>
        /// Validate <see cref="LanguageXmlNamespace"/>
        /// </summary>
        /// <returns>Null if the <see cref="LanguageXmlNamespace"/> is valid, string containging an error otherwise</returns>
        private string ValidateLanguageXmlNamespace()
        {
            if (string.IsNullOrEmpty(languageXmlNamespace))
            {
                return "Must not be null";
            }
            if (languageXmlNamespace.Contains(" ") || languageXmlNamespace.Contains("\t"))
            {
                return "Must not contain spaces and tabs";
            }

            return null;
        }

        /// <summary>
        /// Notify about a new error during validation
        /// </summary>
        /// <param name="columnName">Name of the column being validated</param>
        /// <param name="error">Error message found during a validation</param>
        private void NotifyError(string columnName, string error)
        {
            if (error == null)
            {
                if (errorsDictionary.ContainsKey(columnName))
                {
                    errorsDictionary.Remove(columnName);
                }
            } 
            else
            {
                if (errorsDictionary.ContainsKey(columnName))
                {
                    errorsDictionary[columnName] = error;
                } else
                {
                    errorsDictionary.Add(columnName, error);
                }
            }

            RaisePropertyChanged(() => this.ValidationErrors);
        }

        #region IDataErrorInfo

        public string Error
        {
            get { throw new System.NotImplementedException(); }
        }

        public string this[string columnName]
        {
            get
            {
                string validationResult;
                switch (columnName)
                {
                    case "LanguageName":
                        validationResult = this.ValidateLanguageName();

                        this.NotifyError(columnName, validationResult);
                        break;
                    case "LanguageXmlNamespace":
                        validationResult = this.ValidateLanguageXmlNamespace();

                        this.NotifyError(columnName, validationResult);
                        break;
                    default:
                        throw new ApplicationException("Unknown Property being validated.");
                }
                return validationResult;
            }
        }

        #endregion
    }
}
